#include <stdlib.h>
#include "uart.h"
#include "stm32f10x.h"

#define RCC_APB2Periph_GPIOx        RCC_APB2Periph_GPIOA
#define RCC_APB2Periph_USARTx       RCC_APB2Periph_USART1

#define TERMINAL_USART_DR_TX            (uint32_t)(&USART1->DR)
#define TERMINAL_USART_DR_RX            (uint32_t)(&USART1->DR)
#define TERMINAL_USART                  USART1
#define TERMINAL_USART_IRQN_TX          USART1_IRQn
#define TERMINAL_USART_PIN_TX           GPIO_Pin_9
#define TERMINAL_USART_PIN_RX           GPIO_Pin_10
#define TERMINAL_USART_GPIO             GPIOA
#define TERMINAL_USART_BADURTE          115200

void usart_init(void)
{
    USART_InitTypeDef USART_InitStructure;
    GPIO_InitTypeDef GPIO_InitStructure;

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOx | RCC_APB2Periph_USARTx, ENABLE);

    GPIO_InitStructure.GPIO_Pin = TERMINAL_USART_PIN_TX;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_Init(TERMINAL_USART_GPIO, &GPIO_InitStructure);

    GPIO_InitStructure.GPIO_Pin = TERMINAL_USART_PIN_RX;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
    GPIO_Init(TERMINAL_USART_GPIO, &GPIO_InitStructure);

    USART_InitStructure.USART_BaudRate = TERMINAL_USART_BADURTE;
    USART_InitStructure.USART_WordLength = USART_WordLength_8b;
    USART_InitStructure.USART_StopBits = USART_StopBits_1;
    USART_InitStructure.USART_Parity = USART_Parity_No;
    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
    USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
    USART_Init(TERMINAL_USART, &USART_InitStructure);

    USART_Cmd(USART1, ENABLE);
    USART_ClearFlag(TERMINAL_USART, USART_FLAG_TC | USART_FLAG_RXNE);
    
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
    
    GPIO_WriteBit(GPIOA, GPIO_Pin_8, Bit_RESET);
}

bool serial_in(uint8_t *pchByte)
{
    if (NULL == pchByte) {
        return false;
    }
    
    GPIO_WriteBit(GPIOA, GPIO_Pin_8, Bit_RESET);
    
    if (USART_GetFlagStatus(TERMINAL_USART, USART_FLAG_RXNE) == SET) {
        *pchByte = USART_ReceiveData(TERMINAL_USART);
        return true;
    }
    
    return false;
}

bool serial_out(uint8_t chByte)
{    
    GPIO_WriteBit(GPIOA, GPIO_Pin_8, Bit_SET);
    
    while(!(TERMINAL_USART->SR & USART_FLAG_TC));
    
    if (TERMINAL_USART->SR & USART_FLAG_TC) {
        TERMINAL_USART->DR = chByte;
        
        while(!(TERMINAL_USART->SR & USART_FLAG_TC));
        
        return true;
    }
    
    return false;
}
